#include "parser.h"
#include "translator.h"
#include "cfg.h"

#define _CFG 1
#define _TAC 2
#define _C	3
#define _REP 4

#define _NOPT	0
#define _SCP 1
#define _DSE 2

void IR2C(IR& ir, ostream& o){
	Translator translator(ir.instructions);
	translator.translate();
	translator.output(o);
}

void buildCFG(IR&ir, vector<CFG *>& cfg){
	int start = 1;
	int end;
	while(start < ir.instructions.size()){
		CFG * pCFG = new CFG(ir.instructions);
		if(pCFG->build(start) == false){
			delete pCFG;
			return;
		}
		cfg.push_back(pCFG);
		start = pCFG->end + 1;
	}
}

void deleteCFG(vector<CFG *>& cfg){
	for(int i = 0 ; i < cfg.size(); i++){
		delete cfg[i];
	}
	cfg.clear();
}

void printCFG(vector<CFG *>& cfg, ostream& o){
	for(int i = 0; i < cfg.size(); i++){
		cfg[i]->output(o);
	}
}

void dseReport(vector<CFG *>& cfg, ostream& o){
	for(int i = 0; i < cfg.size(); i++){
		o<<"Function: "<< cfg[i]->entry<<endl;
		o<<"Number of statements eliminated in SCR: "<< cfg[i]->dseInSCR<<endl;
		o<<"Number of statements eliminated not in SCR: "<<cfg[i]->dseOutSCR<<endl;
	}
}

void findSCR(vector<CFG *>& cfg){
	for(int i = 0; i < cfg.size(); i++){
		cfg[i]->findSCR();
	}
}

void printSCR(vector<CFG *>& cfg, ostream& o){
	for(int i = 0; i < cfg.size(); i++){
		cfg[i]->printSCR(o);
	}
}

void scp(vector<CFG *>& cfg){
	for(int i = 0; i < cfg.size(); i++){
		cfg[i]->scp();
	}
}

void scpReport(vector<CFG *>& cfg, ostream& o){
	for(int i = 0; i < cfg.size(); i++){
		cfg[i]->printSCP(o);
	}
}

int main(int argc, char * argv[]){


	string s;
	string arg;
	int do_scp = 0;
	int do_dse = 0;
	int backend = 0;
	if(argc == 2 || argc == 3){
		for(int i = 1; i < argc; i++){
			s = argv[i]; 
			if(s.find("-opt=") != string::npos){
				if(s.find("scp") != string::npos)
					do_scp = 1;
				if(s.find("dse") != string::npos)
					do_dse = 1;
			}
			
			if(s.find("-backend=") != string::npos){
				arg = s.substr(9);
				if(arg.compare("c") == 0)
					backend = _C;
				else if(arg.compare("cfg") == 0)
					backend = _CFG;
				else if(arg.compare("3addr") == 0)
					backend = _TAC;
				else if(arg.compare("rep") == 0)
					backend = _REP;
			}
		}
	}

	if(backend == 0){
		cout << "usage: "<<endl;//todo
	}

	ostream& o = cout;


	IR ir(cin);
	vector<CFG *> vCFG;
	buildCFG(ir, vCFG);
	findSCR(vCFG);

	if(do_scp == 1){
		scp(vCFG);
	}

	if(do_dse == 1){
		for(int i = 0; i < vCFG.size(); i++){
			do{
				vCFG[i]->liveness();
				//vCFG[i]->printLiveness(cout);
			}while(vCFG[i]->dse());
		}
		ir.refine();
	}

	switch(backend){
		case _C: IR2C(ir, o); break;
		case _CFG:
			if(do_dse == 1){
				deleteCFG(vCFG);
				buildCFG(ir, vCFG);
			}
			printCFG(vCFG, o); break;
		case _TAC: ir.print(o); break;
		case _REP:
			if(do_scp == 1){
				scpReport(vCFG, o);
			}
			if(do_dse == 1){
				
				dseReport(vCFG, o);
			} 
	}

	deleteCFG(vCFG);
	return 0;

}
